//! import "common\Base.j"
//! import "common\Tree.j"

library SpellSystem initializer Init requires Base, Tree

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SetSpellInit(integer, function)
// SetSpellReadyProcess(integer, function)
// SetSpellStartProcess(integer, function)
// SetSpellEffectProcess(integer, function)
// SetSpellFinishProcess(integer, function)
// SetSpellStopProcess(integer, function)
// SetSpellLearnProcess(integer, function)
// InitSpell(integer)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

//! runtextmacro TreeSimple("integer", "InitTable")
//! runtextmacro TreeSimple("integer", "SpellTable")

function interface SpellInit takes integer id returns nothing
function interface SpellProcess takes unit caster, integer id returns nothing

globals
	private SpellInit array inits
	private SpellProcess array readys
	private SpellProcess array starts
	private SpellProcess array effects
	private SpellProcess array finishs
	private SpellProcess array stops
	private SpellProcess array learns
endglobals

function SetSpellInit takes integer id, SpellInit init returns nothing
	set inits[InitTable.Insert(id)] = init
endfunction

function SetSpellReadyProcess takes integer id, SpellProcess proc returns nothing
	set readys[SpellTable.Insert(id)] = proc
endfunction

function SetSpellStartProcess takes integer id, SpellProcess proc returns nothing
	set starts[SpellTable.Insert(id)] = proc
endfunction

function SetSpellEffectProcess takes integer id, SpellProcess proc returns nothing
	set effects[SpellTable.Insert(id)] = proc
endfunction

function SetSpellFinishProcess takes integer id, SpellProcess proc returns nothing
	set finishs[SpellTable.Insert(id)] = proc
endfunction

function SetSpellStopProcess takes integer id, SpellProcess proc returns nothing
	set stops[SpellTable.Insert(id)] = proc
endfunction

function SetSpellLearnProcess takes integer id, SpellProcess proc returns nothing
	set learns[SpellTable.Insert(id)] = proc
endfunction

function InitSpell takes integer id returns nothing
	local SpellInit old
	local integer index = InitTable.Find(id)
	if index == 0 then
		return
	endif
	set old = inits[index]
	set inits[index] = 0
	if old != 0 then
		call old.execute(id)
	endif
endfunction

private function Action takes integer id, eventid e returns nothing
	local integer i = SpellTable.Find(id)
	if i == 0 then
		return
	endif
	if e == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
		if readys[i] != 0 then
			call readys[i].execute(GetTriggerUnit(), id)
		endif
	elseif e == EVENT_PLAYER_UNIT_SPELL_CAST then
		if starts[i] != 0 then
			call starts[i].execute(GetTriggerUnit(), id)
		endif
	elseif e == EVENT_PLAYER_UNIT_SPELL_EFFECT then
		if effects[i] != 0 then
			call effects[i].execute(GetTriggerUnit(), id)
		endif
	elseif e == EVENT_PLAYER_UNIT_SPELL_FINISH then
		if finishs[i] != 0 then
			call finishs[i].execute(GetTriggerUnit(), id)
		endif
	elseif e == EVENT_PLAYER_UNIT_SPELL_ENDCAST then
		if stops[i] != 0 then
			call stops[i].execute(GetTriggerUnit(), id)
		endif
	elseif e == EVENT_PLAYER_HERO_SKILL then
		if learns[i] != 0 then
			call learns[i].execute(GetTriggerUnit(), id)
		endif
	endif
endfunction

private function LearnSpell takes nothing returns boolean
	local integer id = GetLearnedSkill()
	call InitSpell(id)
	call Action(id, EVENT_PLAYER_HERO_SKILL)
	return false
endfunction

private function CastSpell takes nothing returns boolean
	call Action(GetSpellAbilityId(), GetTriggerEventId())
	return false
endfunction

private function Init takes nothing returns nothing
	local trigger t
	set t = CreateTrigger()
	call TriggerAddCondition(t, Condition(function CastSpell))
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH)
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
	set t = CreateTrigger()
	call TriggerAddCondition(t, Condition(function LearnSpell))
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
	set t = null
endfunction

endlibrary